﻿(function(window){
var 
	aider = function(){
			
		var aidobj = {
			
			init : function(contextP){
				
				this.ref = contextP;
								
			},
			extend : function(destination, source, override){
				if(override === undefined)
					override = true;
				for(var property in source){
					if(override || !(property in destination)){
						destination[property] = source[property];
					}
				}
				return destination;
			},
			wrapper : function(me, parent){
				var ins = function(){
					me.apply(this, arguments);
				};
				var subclass = function(){};
				subclass.prototype = parent.prototype;
				ins.prototype = new subclass;
				return ins;
			},
			/**
				set some style
				to element
			*/
			setStyle : function(elems, style, value){
				
				if(!elems.length){
					elems = [elems];
				}
				
				if(typeof style == 'string'){
					var s = style;
					style = {};
					style[s] = value;
				}
				
				for(var i=0; i<elems.length; i++){
					var elem = elems[i];
				    for(var name in style){
						var value = style[name];
						if(name == 'opacity' && aidobj.browser.ie){
							elem.style.filter = 
								(elem.currentStyle.filter || '')
								.replace(/alpha\([^)]*\)/, '') +
								'alpha(opacity=' + value * 100 + ')';
						}else if(name == 'float'){
							elem.style[aidobj.browser.ie ? 
								'styleFloat' : 'cssFloat']
								= value;
						}else{
							elem.style[aidobj.legal(name)] = value;
						}
					}
				}
			},
			/**
				get current style
				object
			*/
			curStyle : document.defaultView ?
			function(elem){
				return document.defaultView
						.getComputedStyle(elem, null);	   
			} : 
			function(elem){
				return elem.currentStyle;
			},
			/**
				get current style 
				of element
			*/
			getStyle : document.defaultView ?
			function(elem, name){
				var 
					style = document.defaultView
								.getComputedStyle(elem, null);
				return name in style ?
					style[name] : style.getPropertyValue(name);
			} :
			function(elem, name){
				var 
					style = elem.style,
					curStyle = elem.currentStyle;
				
				if(name == 'opacity'){
					if(/alpha\(opacity=(.*)\)/i.test(curStyle.filter)){
						var 
							opacity = parseFloat(RegExp.$1);
							return opacity ? opacity / 100 : 0;
					}
					return 1;
				}else if(name == 'float'){
					name = 'styleFloat';
				}
				
				var 
					ret = curStyle[name] || curStyle[aidobj.legal(name)];
					if(!/^-?\d+(?:px)?$/i.test(ret) && /^\-?\d/.test(ret)){
						var 
							left = style.left,
							rsStyle = elem.runtimeStyle,
							rsLeft = rtStyle.left;
						
						rtStyle.left = curStyle.left;
						style.left = ret || 0;
						ret = style.pixelLeft + 'px';
						style.left = left;
						rtStyle.left = rsLeft;
					}
				
				return ret;
			},
			legal : function(s){
				return s.replace(/-([a-z])/ig, function(all, letter){
					return letter.toUpperCase();
				});
			},
			/**
				we can detect our
				own browser
			*/
			browser : function(ua){
				var 
					b = {
						msie : /msie/.test(ua) && !/opera/.test(ua),
						opera : /opera/.test(ua),
						safari : /webkit/.test(ua) && !/chrome/.test(ua),
						firefox : /firefox/.test(ua),
						chrome : /chrome/.test(ua)
					},
					vMark = '';
				
				for(var i in b){
					if(b[i]){
						vMark = 'safari' == i ? 'version' : i;
						break;
					}
				}
				
				b.version = 
					vMark && 
					RegExp('(?:' + vMark + ')[\\/: ]([\\d.]+)').test(ua) ?
					RegExp.$1 : '0';
				b.ie = b.msie;
				b.ie6 = b.msie && parseInt(b.version, 10) == 6;
				b.ie7 = b.msie && parseInt(b.version, 10) == 7;
				b.ie8 = b.msie && parseInt(b.version, 10) == 8;
				
				return b;
			}(window.navigator.userAgent.toLowerCase()),
			/**
				we can define our
				own events
			*/
			selfe : function(object, type, handler){
				var 
					guid = 1;
				
				return {
					addEvent : function(object, type, handler){
						if(!handler.$$$guid)
							handler.$$$guid = guid++;
						
						if(!object.cusevents)
							object.cusevents = {};
							
						if(!object.cusevents[type])
							object.cusevents[type] = {};
						
						object.cusevents[type][handler.$$$guid] = handler;
					},
					
					removeEvent : function(object, type, handler){
						if(object.cusevents && object.cusevents[type]){
							delete object.cusevents[type][handler.$$$guid];
						}
					},
					
					fireEvent : function(object, type){
						if(!object.cusevents)
							return;
						
						var args = Array.prototype.slice.call(arguments, 2),
							handlers = object.cusevents[type];
							
						for(var i in handlers){
							handlers[i].apply(object, args);
						}
					},
					
					clearEvent : function(object){
						if(!object.cusevents)
							return;
						
						for(var type in object.cusevents){
							var handlers = object.cusevents[type];
							for(var i in handlers){
								handlers[i] = null;
							}
							object.cusevents[type] = null;
						}
						
						object.cusevents = null;
					}
				}
			}(),
			/**
				change the context of
				the function
			*/
			bind : function(fn, context){
				var 
					slice = Array.prototype.slice,
					args = slice.call(arguments, 2);
				
				return function(){
					return fn.apply(context,
						args.concat(slice.call(arguments)));
				};
			},
			getScrollTop : function(node){
				var 
					doc = node ? node.ownerDocument : document;
				
				return doc.documentElement.scrollTop || doc.body.scrollTop;
			},
			getScrollLeft : function(node){
				var 
					doc = node ? node.ownerDocument : document;
					
				return doc.documentElement.scrollLeft || doc.body.scrollLeft;
			},
			contains : document.defaultView ?
			function(a, b){
				return !!(a.compareDocumentPosition(b) & 16)
			} :
			function(a, b){
				return a !=b && a.contains(b);
			},
			rect : function(node){
				var 
					left = 0,
					top = 0,
					right = 0,
					bottom = 0;
				if(!node.getBoundingClientRect || this.browser.ie8){
					var n = node;
					while(n){
						left += n.offsetLeft,
						top += n.offsetTop;
						n = n.offsetParent;
					}
					right = left + node.offsetWidth;
					bottom = top + node.offsetHeight;
				}else{
					var rect = node.getBoundingClientRect();
					left = right = this.getScrollLeft(node);
					top = bottom = this.getScrollTop(node);
					left += rect.left;
					right += rect.right;
					top += rect.top;
					bottom += rect.bottom;
				}
				return {
					'left' : left,
					'top' : top,
					'right' : right,
					'bottom' : bottom
				}
			},
			clientRect : function(node){
				var 
					rect = this.rect(node),
					sLeft = this.getScrollLeft(node),
					sTop = this.getScrollTop(node);
				rect.left -= sLeft;
				rect.right -= sLeft;
				rect.top -= sTop;
				rect.bottom -= sTop;
				return rect;
			},
			/**
				you can bind multiple events
				on an element
			*/
			helpe : function(){
				var 
					removeEvent,
					addEvent, 
					guid = 1,
					storage = function(element, type, handler){
						
						if(!handler.$$guid)
							handler.$$guid = guid++;
							
						if(!element.events)
							element.events = {};
						
						var handlers = element.events[type];
						if(!handlers){
							handlers = element.events[type] = {};
							if(element['on' + type]){
								handlers[0] = element['on' + type];
							}
						}
					};
				
				if(window.addEventListener){
					var 
						fix = {
							'mouseenter' : 'mouseover',
							'mouseleave' : 'mouseout'
						};
					
					addEvent = function(element, type, handler){
						if(type in fix){
							
							storage(element, type, handler);
							var 
								fixhandler = 
								element.events[type][handler.$$guid] = 
								function(event){
									var 
										related = event.relatedTarget;
									if(!related || 
										(element != related &&
										!(element.compareDocumentPosition(related) & 16))){
										    
										handler.call(this, event);
									}
								};
							
							element.addEventListener(fix[type], fixhandler, false);
						}else{
							
							element.addEventListener(type, handler, false);
						}
					};
					
					removeEvent = function(element, type, handler){
						if(type in fix){
							if(element.events && 
								element.events[type]){
								
								element.removeEventListener(fix[type],
									element.events[type][handler.$$guid],
									false);
								delete element.events[type][handler.$$guid];
							}
						}else{
						
							element.removeEventListener(type, handler, false);
						}
					};
				}else{
					
					addEvent = function(element, type, handler){
						storage(element, type, handler);
						element.events[type][handler.$$guid] = handler;
						element['on' + type] = handleEvent;
					};
					
					removeEvent = function(element, type, handler){
						if(element.events && element.events[type]){
							delete element.events[type][handler.$$guid];
						}
					};
					
					function handleEvent(){
						var 
							returnValue = true,
							event = fixEvent(),
							handlers = this.events[event.type];
						
						for(var i in handlers){
							
							this.$$handleEvent = handlers[i];
							if(this.$$handleEvent(event) === false){
								
								returnValue = false;
							}
						}
						return returnValue;
					}
				}
				
				function fixEvent(event){
					if(event)
						return event;
					
					event = window.event;
					event.pageX = event.clientX + aidobj.getScrollLeft(event.srcElement);
					event.pageY = event.clientY + aidobj.getScrollTop(event.srcElement);
					event.target = event.srcElement;
					event.stopPropagation = stopPropagation;
					event.preventDefault = preventDefault;
					
					var relatedTarget = {
						'mouseout' : event.toElement,
						'mouseover' : event.fromElement
					}[event.type];
					
					if(relatedTarget){
						event.relatedTarget = relatedTarget;
					}
					
					return event;
				};
				
				function stopPropagation(){
					this.cancelBubble = true;
				};
				
				function preventDefault(){
					this.returnValue = false;
				};
				
				return {
					'addEvent' : addEvent,
					'removeEvent' : removeEvent,
					'fixEvent' : fixEvent
				}
			}(),
			
			isArray : function(obj){
				return Object.prototype
						.toString.call(obj) === '[object Array]';
			},
			
			indexOf : function(array, elt, from){
				if(array.indexOf){
					return isNaN(from) ? array.indexOf(elt) :
										array.indexOf(elt, from);
				}else{
					var len = array.length;
					from = isNaN(from) ? 0 :
							from < 0 ? Math.ceil(from) + len :
										Math.floor(from);
					
					for(; from<len; from++){
					    if(array[from] === elt) 
							return from;
					}
					return -1;
				}
			},
			
			lastIndexOf : function(array, elt, from){
				if(array.lastIndexOf){
					return isNaN(from) ? array.lastIndexOf(elt) :
										array.lastIndexOf(elt, from);
				}else{
					var len = array.length;
					from = isNaN(from) || from >= len - 1 ? len - 1 :
							from < 0 ? Math.ceil(from) + len :
										Math.floor(from);
					for(; from>-1; from--){
						if(array[from] === elt)
							return from
					}
					
					return -1;
				}
			},
			
			plugin : function(object, callback){
				if(undefined === object.length){
					for(var name in object){
						if(false === callback(object[name], name, object))
							break;
					}
				}else{
					for(var i=0, len=object.length; i<len; i++){
						if(i in object){
							if(false === callback(object[i], i, object))
								break;
						}
					}
				}
			}
		};
		
		var each = aidobj.plugin;
		/**
			filter  --  按指定函数过滤元素，汇集返回值为true元素组成新的数组
			forEach --	在每一个元素上执行函数，函数返回类型为空
			every   --  贪婪的试图匹配每一个元素，直到有一个返回false为止
			some    --  懒惰的企图找到一个元素合乎要求，只要有一个返回true停止
			map     --	使用同一函数处理每一个元素并返回，汇集返回结果组成新数组
		*/
		each({
			forEach : function(object, callback, thisp){
				each(object, function(){
					callback.apply(thisp, arguments)
				})
			},
			map : function(object, callback, thisp){
				var ret = [];
				each(object, function(){
					ret.push(callback.apply(thisp, arguments));
				});
				return ret;
			},
			filter : function(object, callback, thisp){
				var ret = [];
				each(object, function(item){
					callback.apply(thisp, arguments) && ret.push(item);
				});
				return ret;
			},
			every : function(object, callback, thisp){
				var ret = true;
				each(object, function(){
					if(!callback.apply(thisp, arguments)){
						ret = false;
						return false;
					}
				});
				return ret;
			},
			some : function(object, callback, thisp){
				var ret = false;
				each(object, function(){
					if(callback.apply(thisp, arguments)){
						ret = true;
						return false;
					}
				});
				return ret;
			}
		}, 
		function(method, name){
			aidobj[name] = function(object, callback, thisp){
				if(object[name]){
					return object[name](callback, thisp);
				}else{
					return method(object, callback, thisp);
				}
			}
		});
		
		return aidobj;
	}();

window.$$OBEA = aider;	
})(window)